﻿namespace ConsoleApp1
{
    public class TaskDemo
    {
        public void Init()
        {
            Console.WriteLine("我和老婆正在看电视，线程Id为：{0}", GetThreadId());
            Console.WriteLine("突然停电了，快去看下是不是跳闸了");
            Task task2 = CommandOpenMainsSwitch();
            Console.WriteLine("没电了先玩会儿手机吧，线程Id为：{0}", GetThreadId());
            Thread.Sleep(100);
            Console.WriteLine("手机也没电了只等电源打开，线程Id为：{0}", GetThreadId());

            //task.Wait();    //所以这里将被阻塞，直到任务完成
            //或者
            while (!task2.IsCompleted) { Thread.Sleep(100); }

            Console.WriteLine("又有电了我们继续看电视，线程Id为：{0}", GetThreadId());
            Console.ReadLine();

            double aaa = 8955.5241;

            Task<string> task = Task.Run(() =>
            {
                Console.WriteLine("另一个线程在运行！");  // 这句话只会被执行一次
                //Thread.Sleep(2000);
                return "Hello World";
            });

            // 这里主线程会挂起等待，直到task执行完毕我们拿到返回结果
            Console.WriteLine("yyyyyyyyyyyyyyyyyyyyyyyy");
            Console.WriteLine(task.Result);

            var list = new string[] { "1", "2" };

            var task3 = new TaskFactory().StartNew(() =>
            {
                try
                {
                    Parallel.ForEach<string>(list, new ParallelOptions()
                    {
                        MaxDegreeOfParallelism = Environment.ProcessorCount - 1
                    }, (item, loopState) =>
                    {
                        Console.WriteLine(item);
                    });
                }
                catch (Exception ce)
                {
                }
            });
            task3.ContinueWith(t =>
            {
                Console.WriteLine(1);
                switch (t.Status)
                {
                    case TaskStatus.Canceled:
                        break;

                    case TaskStatus.Faulted:
                        break;

                    case TaskStatus.RanToCompletion:
                        break;

                    default:
                        break;
                }
                t.Dispose();
            });

            Thread.Sleep(100);
        }

        private static async Task Test()
        {
            // 方法打上async关键字，就可以用await调用同样打上async的方法
            // await 后面的方法将在另外一个线程中执行
            await GetName();
        }

        private static async Task GetName()
        {
            // Delay 方法来自于.net 4.5
            await Task.Delay(1000);  // 返回值前面加 async 之后，方法里面就可以用await了
            Console.WriteLine("Current Thread Id :{0}", Thread.CurrentThread.ManagedThreadId);
            Console.WriteLine("In antoher thread.....");
        }

        /// <summary>
        /// 通知我去打开电源开关
        /// </summary>
        public static async Task CommandOpenMainsSwitch()
        {
            //将后续代码交给线程池执行
            //将后续代码交给线程池执行
            Console.WriteLine(111111111);
            await Task.Run(() => { Thread.Sleep(3000); }).ConfigureAwait(false);
            Console.WriteLine(222222222222);
            Thread.Sleep(3000);
            Console.WriteLine(3333333333);
            Console.WriteLine("这时我准备去打开电源开关，线程Id为：{0}", GetThreadId());
            await Task.Run(() =>
            {
                Console.WriteLine("屁颠屁颠的去打开电源开关，线程Id为：{0}", GetThreadId());
                Thread.Sleep(1000);
            }).ConfigureAwait(true);

            Console.WriteLine("电源开关打开了，线程Id为：{0}", GetThreadId());
        }

        public static async Task<string> DoCurlAsync()
        {
            using (var httpClient = new HttpClient())
            using (var httpResonse = await httpClient.GetAsync("https://www.bynder.com"))
            {
                Console.WriteLine(1111111111);
                return await httpResonse.Content.ReadAsStringAsync();
            }
        }

        private static string GetThreadId()
        {
            return Thread.CurrentThread.ManagedThreadId.ToString();
        }

        #region 调用

        public static async Task One()
        {
            #region 多线程单个任务

            //无参

            //直接开始执行任务
            //Go==()=>{"我是GO线程"}
            new Thread(Go).Start();  // .NET 1.0开始就有的
            Task task = Task.Factory.StartNew(Go); // .NET 4.0 引入了 TPL
            task = new TaskFactory().StartNew(Go); // .NET 4.0 引入了 TPL
            task = Task.Run(new Action(Go)); // .NET 4.5 新增了一个Run的方法
            task = Task.Run(() => { Console.WriteLine("1"); });
            //创建Task
            task = new Task(Go);// task = new Task(() => { Console.WriteLine("1"); });
            task.Start();//多线程开始执行,此句可省略
            task.Wait();// 等待单线程执行完毕，这里是指GO方法
            //这里Go 方法没有返回值

            //有参
            new Thread(() => Go("111111")).Start();
            Task task2 = Task.Factory.StartNew(() => Go("222222"));
            task = Task.Run(() => Go("33333"));
            task = new Task(() => Go("44444"));
            task.Start();
            task.Wait();

            await Go2();//直接调用
            string go3 = await Go3();
            var task3 = Go3();
            task3.Wait();
            go3 = task3.Result;

            #endregion 多线程单个任务
        }

        public static async Task More()
        {
            #region 多线程执行多个任务

            //WhenAll   需要获取多个返回值时调用
            //WhenAny   有一个有返回值时就往下走
            //WaitAny   多个任务有一个执行完毕就继续往下走
            //WaitAll   等待多个任务完成后往下走，无返回值

            var taskList = new List<Task<int>>
            {
                MyMethodAsync(),
                tasklist()
            };

            //此方式不推荐 //var taskres = await Task.WhenAll(taskList);
            var taskres = await Task.WhenAll(taskList).ConfigureAwait(false);//加上ConfigureAwait(false) 防止死锁，不需要上下文参数变量
            var taskres2 = await Task.WhenAny(taskList).ConfigureAwait(false);
            var taskres3 = Task.WaitAny(taskList.ToArray());
            Task.WaitAll(taskList.ToArray());
            var taskres4 = Task.WaitAll(taskList.ToArray(), -1);

            Console.WriteLine(taskres[0]);

            #endregion 多线程执行多个任务
        }

        #endregion 调用

        #region 方法Demo

        public static void Go()
        {
            Console.WriteLine("我是GO线程");
        }

        public static void Go(string a)
        {
            Console.WriteLine(a);
        }

        public static async Task Go2()
        {
            await Task.Delay(1);
            Console.WriteLine("我是GO2线程");
        }

        public static async Task<string> Go3()
        {
            return await Task.FromResult("1000");
        }

        public static async Task<int> MyMethodAsync()
        {
            return await Task.FromResult(1000);
        }

        public static async Task<int> tasklist()
        {
            return await Task.FromResult(2000);
        }

        #endregion 方法Demo
    }
}